package com.jfinal.core;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.jfinal.aop.Interceptor;
import com.jfinal.config.Interceptors;


/**
 * CMS中的action
 * @author Marc
 * @version 1.0
 */
public class CMSActionMapping {
	
	public Map<String,Action> mapping = new HashMap<String,Action>();
	
	private Logger log = Logger.getLogger(CMSActionMapping.class);
	
	InterceptorBuilder interceptorBuilder = new InterceptorBuilder();
	
	private static  Interceptors interceptors = Config.getInterceptors();

	private static final String SLASH = "/";
	
	Set<String> excludedMethodName  = null ; 
	
	private enum ActionType{
		ClassType("Class"),
		MethodType("Method") ;
		private String typeStr = null ; 
		private ActionType(String type){
			this.typeStr = type ;
		}
		public String toString(){
			return this.typeStr;
		}
		
	}
	
	/**
	 * 
	 * @user Marc
	 * @createtime 2014-8-13 上午11:38:48
	 * @return
	 */
	public String getAdminURL() {
		Collection<Action> collection = mapping.values();
		Iterator<Action> iter = collection.iterator();
		while(iter.hasNext()){
			CMSAction action  = (CMSAction) iter.next();
			if(action.getIsAdmin() && action.getMethod().getName().equals("index") ){
				String actionKey = action.getActionKey();
				if(!actionKey.endsWith("/"))
					actionKey = actionKey+"/";
				return actionKey;
			}
		}
		return "/";
	}

	public Action getAction(String target, String[] urlPara) {
		target = target.toUpperCase(); 
		Action action = mapping.get(target);
		if (action != null) {
			return action;
		}
		
		// --------
		int i = target.lastIndexOf(SLASH);
		if (i != -1) {
			action = mapping.get(target.substring(0, i));
			urlPara[0] = target.substring(i + 1);
		}
		return action;
	}
	
	/***
	 * 父类中存在的方法集合
	 * @user Marc
	 * @createtime 2015-1-12 下午03:02:04
	 * @return
	 */
	private Set<String> getExcludedMethodName() {
		if(excludedMethodName  == null){
			excludedMethodName = new HashSet<String>();
			Method[] methods = net.onewfour.control.BaseControl.class.getMethods();
			for (Method m : methods) {
				if (m.getParameterTypes().length == 0){
					excludedMethodName.add(m.getName());
				}
			}
		}
		return excludedMethodName;
	}

	public void addAction(String url, String action,String type, String note,int isAdmin) {
		try {
			int i = action.lastIndexOf(".");
			if(i==-1){
				return ; 
			}
			String classStr = null ; 
			String methodStr = null ; 
			if(type.equals(ActionType.ClassType.toString())){
				classStr = action;
			}else if(type.equals(ActionType.MethodType.toString())){
				classStr = action.substring(0,i);
				methodStr = action.substring(i+1,action.length());
			}else{
				log.debug("初始化类型:"+type+";Action:"+action);
				return;
			}
			
			Interceptor[] defaultInters = interceptors.getInterceptorArray();
			interceptorBuilder.addToInterceptorsMap(defaultInters);
			Class<? extends Controller> controllerClass = (Class<? extends Controller>) Class.forName(classStr);
			
			Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);
//			Method method = controllerClass.getMethod(methodStr);
//			Method[] methods = controllerClass.getMethods();
			/**
			 * 规定有方法来进行初始化Action
			 */
			log.debug("开始初始化Class中的Method");
			Method[] methods = null ; 
			if(type.equals(ActionType.ClassType.toString())){
				methods = controllerClass.getMethods();
			}else if(type.equals(ActionType.MethodType.toString())){
				Method method = controllerClass.getMethod(methodStr);
				methods = new Method[]{method};
			}
			
			for (int j = 0; j < methods.length; j++) {
				Method method = methods[j];
				String methodName = method.getName();
				if(method.getParameterTypes().length != 0 )
					continue;
				if(!"void".equals(method.getReturnType().toString()))
					continue ;
				if(getExcludedMethodName().contains(methodName) )
					continue;
				
				Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method);
				Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(defaultInters, controllerInters, controllerClass, methodInters, method);
				
				/**
				 * 方法有ActionKey
				 */
				ActionKey ak = method.getAnnotation(ActionKey.class);
				if (ak != null) {
					String actionKey = ak.value().trim();
					actionKey = actionKey.toUpperCase();
					if ("".equals(actionKey))
						throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
					
					if (!actionKey.startsWith(SLASH))
						actionKey = SLASH + actionKey;
					
					if (mapping.containsKey(actionKey)) {
						warnning(actionKey, controllerClass, method);
					}
					
					Action actionCMS = new CMSAction(url, actionKey, controllerClass, method, methodName, actionInters, url, note,type,isAdmin);
					mapping.put(actionKey, actionCMS);
				}
				else if (methodName.equals("index")) {
					String actionKey = url;
					actionKey = actionKey.toUpperCase();
					Action actionCMS = new CMSAction(url, actionKey, controllerClass, method, methodName, actionInters, url, note,type,isAdmin);
					actionCMS = mapping.put(actionKey, actionCMS);
					
					if (actionCMS != null) {
						warnning(actionCMS.getActionKey(), actionCMS.getControllerClass(), actionCMS.getMethod());
					}
				}
				else {
					String actionKey = url.equals(SLASH) ? SLASH + methodName : url + SLASH + methodName;
					actionKey = actionKey.toUpperCase();
					if (mapping.containsKey(actionKey)) {
						warnning(actionKey, controllerClass, method);
					}
					
					Action actionCMS = new CMSAction(url, actionKey, controllerClass, method, methodName, actionInters, url, note,type,isAdmin);
					mapping.put(actionKey, actionCMS);
				}
				log.debug("初始化Action:"+action+";Type:"+type+";Method:"+method.getName()+";URL:"+url+"; 成功");
			}
			
		} catch (Exception e) {
			log.error("初始化Action:"+action+";Type:"+type+";URL:"+url+";失败",e);
		} 
	}
	
	

	
	private static final void warnning(String actionKey, Class<? extends Controller> controllerClass, Method method) {
		StringBuilder sb = new StringBuilder();
		sb.append("--------------------------------------------------------------------------------\nWarnning!!!\n")
		.append("ActionKey already used: \"").append(actionKey).append("\" \n") 
		.append("Action can not be mapped: \"")
		.append(controllerClass.getName()).append(".").append(method.getName()).append("()\" \n")
		.append("--------------------------------------------------------------------------------");
		System.out.println(sb.toString());
	}

	
	
}
